package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"os"
)

// Client 服务端类
type Client struct {
	ServerIp   string
	ServerPort int
	Name       string
	conn       net.Conn
	flag       int // 用户选择的菜单
}

// 创建client
func NewClient(serverIP string, serverPort int) (client *Client) {
	// 创建客户端对象
	client = &Client{
		ServerIp:   serverIP,
		ServerPort: serverPort,
		flag:       99,
	}
	// 连接server
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", serverIP, serverPort))
	if err != nil {
		fmt.Println("net.Dail error:", err)
		return nil
	}
	client.conn = conn

	return
}

// 显示菜单
func (c *Client) ShowMenus() bool {
	var flag int

	fmt.Println(">> 1.公聊模式")
	fmt.Println(">> 2.私聊模式")
	fmt.Println(">> 3.更改用户名")
	fmt.Println(">> 0.退出")

	fmt.Scanln(&flag)
	if flag >= 0 && flag <= 3 {
		c.flag = flag
		return true
	} else {
		fmt.Println("非法菜单")
		return false
	}
}

// 修改用户名
func (c *Client) UpdateName() bool {
	fmt.Println(">>>> 你选择了更新用户名")
	fmt.Print(">> 请输入新的用户名：")
	fmt.Scanln(&c.Name)

	// 请求服务端重命名
	sendMsg := "rename|" + c.Name + "\n"
	_, err := c.conn.Write([]byte(sendMsg))
	if err != nil {
		fmt.Println("conn.Write error：", err)
		return false
	}

	return true
}

// 公聊模式
func (c *Client) PublicChat() {
	var chatMsg string

	fmt.Println(">>>> 你选择了公聊模式，输入exit退出")
	// 提示用户输入消息
	fmt.Print(">> 请输入聊天内容：")
	fmt.Scanln(&chatMsg)

	// 发给服务器
	for chatMsg != "exit" {
		// 消息不为空，则发送
		if len(chatMsg) != 0 {
			sendMsg := chatMsg + "\n"
			_, err := c.conn.Write([]byte(sendMsg))
			if err != nil {
				fmt.Println("conn.Write error：", err)
				break
			}
		}

		chatMsg = ""
		fmt.Print(">> 请输入聊天内容：")
		fmt.Scanln(&chatMsg)
	}
}

// 查询在线用户
func (c *Client) SelectUsers() {
	sendMsg := "getUsers\n"
	_, err := c.conn.Write([]byte(sendMsg))
	if err != nil {
		fmt.Println("conn.Write error：", err)
		return
	}
}

// 私聊模式
func (c *Client) PrivateChat() {
	fmt.Println(">>>> 你选择了私聊模式，输入users返回用户列表，exit退出")

	// 显示所有用户
	c.SelectUsers()
	fmt.Print(">> 请输入聊天对象的用户名：")

	var remoteName string
	var chatMsg string
	fmt.Scanln(&remoteName)

	for remoteName != "exit" {
		fmt.Println(">> 请输入消息内容：")
		fmt.Scanln(&chatMsg)

		for chatMsg != "exit" {
			// 消息不为空，则发送
			if len(chatMsg) != 0 {
				sendMsg := "to|" + remoteName + "|" + chatMsg + "\n\n"
				_, err := c.conn.Write([]byte(sendMsg))
				if err != nil {
					fmt.Println("conn.Write error：", err)
					break
				}
			}

			chatMsg = ""
			fmt.Print(">> 请输入聊天内容：")
			fmt.Scanln(&chatMsg)
		}

		remoteName = ""
		c.SelectUsers()
		fmt.Print(">> 请输入聊天对象的用户名：")
		fmt.Scanln(&remoteName)
	}
}

// 客户端业务
func (c *Client) Run() {
	for c.flag != 0 {
		for c.ShowMenus() != true {
		}

		// 根据flag处理不同的菜单业务
		switch c.flag {
		case 1:
			// 公聊
			c.PublicChat()
		case 2:
			// 私聊
			c.PrivateChat()
		case 3:
			// 改名
			c.UpdateName()
		}
	}
}

// 处理服务端返回，启用一个go程，以免阻塞其它菜单功能
func (c *Client) DealResponse() {
	// 永久阻塞等待conn的返回
	// 一旦clent有数据，则拷贝到stdout标准输出上
	io.Copy(os.Stdout, c.conn)
	// 等价于
	//for {
	//	buf := make([]byte, 4096)
	//	c.conn.Read(buf)
	//	fmt.Println(buf)
	//}
}

var serverIp string
var serverPort int

// ./client -ip 127.0.0.1 -port 8888
func init() {
	flag.StringVar(&serverIp, "ip", "127.0.0.1", "设置服务端IP，默认127.0.0.1") // 变量、参数、默认值、说明
	flag.IntVar(&serverPort, "port", 8888, "设置服务端端口，默认8888")            // 变量、参数、默认值、说明
}

func main() {
	// 命令行解析，自动解析
	flag.Parse()

	client := NewClient(serverIp, serverPort)
	if client == nil {
		fmt.Println(">>>>>> 服务器连接失败")
		return
	}
	fmt.Println(">>>>>> 服务器连接成功")

	// 处理服务器返回
	go client.DealResponse()

	// 客户端业务
	client.Run()
}
